package com.example.actflow.service;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.GestureDescription;
import android.content.Intent;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.example.actflow.eum.ActionType;
import com.example.actflow.eum.CompareOp;
import com.example.actflow.repository.ContextData;
import com.example.actflow.model.LogicItem;

import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyAccessibilityService extends AccessibilityService {

    private static final String TAG = "MyAccessibilityService";

    private ContextData contextData;

    private boolean isLoading = false;

    ExecutorService executor = Executors.newCachedThreadPool();

    Handler mainHandler = new Handler(Looper.getMainLooper());

    private static final ThreadLocal<LogicItemContext> threadLocal = new ThreadLocal<>();


    @Override
    public void onServiceConnected() {
        super.onServiceConnected();
        contextData = ContextData.getInstance(this);

        Log.i(TAG, "onServiceConnected: 配置 AccessibilityServiceInfo");
        String[] packageNames = contextData.getAppPackageName();
        AccessibilityServiceInfo info = getServiceInfo(); // 先获取 XML 的默认配置
        info.packageNames = packageNames;
        setServiceInfo(info);
        sendBroadcast("true");
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        if (event == null || event.getPackageName() == null) return;

        String pkgName = event.getPackageName().toString();
        int eventType = event.getEventType();

        Log.d(TAG, "事件包名: " + pkgName + ", 类型: " + eventType);
        // 在这里处理你想要的事件
        AccessibilityNodeInfo root = getRootInActiveWindow();
        if (root == null) return;

        if (!isLoading) {
            isLoading = true;
            executor.submit(() -> {

                try {

                    Thread.sleep(500);

                    if(!contextData.isEnable(pkgName)){
                        return;
                    }

                    LogicItem logicItem = contextData.loadConfigForApp(pkgName);

                    Map<String, AccessibilityNodeInfo> variableMap = new HashMap<>();

                    Deque<LogicItem> actionQueue = new LinkedList<>(logicItem.children);
                    threadLocal.set(new LogicItemContext(pkgName, 0));

                    while (true) {
                        LogicItem poll = actionQueue.poll();
                        if (poll == null) {
                            break;
                        }
                        Objects.requireNonNull(threadLocal.get()).index++;

                        if (executeLogic(poll, actionQueue, variableMap, root)) {
                            break;
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    isLoading = false;
                }

            });

        }

    }

    @Override
    public void onInterrupt() {
        Log.i(TAG, "辅助功能被中断");
        sendBroadcast("false");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("Accessibility", "服务已销毁");
        sendBroadcast("false");
        // 在这里执行清理操作
    }

    private void sendBroadcast(String status){
        // 发送应用内广播
        Intent intent = new Intent("AS_BROADCAST");
        intent.putExtra("status", status); // 附加数据

        // 使用LocalBroadcastManager发送（仅限当前应用接收）
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    }

    private boolean executeLogic(LogicItem item, Deque<LogicItem> actionQueue, Map<String, AccessibilityNodeInfo> variableMap, AccessibilityNodeInfo root) {
        if (item.type == LogicItem.Type.CONDITION) {
            boolean result = evaluateCondition(item, variableMap, root);
            if (result) {
                //倒序插入首端
                for (int i = item.children.size() - 1; i >= 0; i--) {
                    actionQueue.addFirst(item.children.get(i));
                }

            }
        } else if (item.type == LogicItem.Type.ACTION) {
            evaluateAction(item, variableMap);
            return true;

        }
        return false;
    }

    private boolean evaluateCondition(LogicItem item, Map<String, AccessibilityNodeInfo> vars, AccessibilityNodeInfo root) {
        CompareOp op = CompareOp.fromDisplayName(item.compareOp);
        boolean match = false;
        if (op != null) {
            if (item.target == null || "全文".equals(item.target)) {
                Optional<AccessibilityNodeInfo> optional = Optional.empty();
                if (op == CompareOp.TEXT_EQUALS) {
                    optional = findNodesByTextEquals(root, item.param).stream().findFirst();
                } else if (op == CompareOp.TEXT_STARTS_WITH) {
                    optional = findNodesByTextStartsWith(root, item.param).stream().findFirst();
                } else if (op == CompareOp.TEXT_ENDS_WITH) {
                    optional = findNodesByTextEndsWith(root, item.param).stream().findFirst();
                }
                if (optional.isPresent()) {
                    vars.put(item.varName, optional.get());
                    match = true;
                }
            } else {
                AccessibilityNodeInfo node = vars.get(item.target);
                if (node != null && node.getText() != null) {
                    CharSequence cs = node.getText();
                    if (cs == null) {
                        cs = node.getContentDescription();
                    }
                    if (cs != null) {
                        String trim = cs.toString().trim();

                        if (op == CompareOp.TEXT_EQUALS) {
                            match = trim.equals(item.param);
                        } else if (op == CompareOp.TEXT_STARTS_WITH) {
                            match = trim.startsWith(item.param);
                        } else if (op == CompareOp.TEXT_ENDS_WITH) {
                            match = trim.endsWith(item.param);
                        } else {

                            Matcher matcher = Pattern.compile("\\d+\\.?\\d*").matcher(trim);
                            if (matcher.find()) {
                                String group = matcher.group();
                                double a = Double.parseDouble(group);
                                double b = Double.parseDouble(item.param);

                                int compare = Double.compare(a, b);

                                if (op == CompareOp.EQUALS) {
                                    match = (compare == 0);
                                } else if (op == CompareOp.GREATER_OR_EQUAL) {
                                    match = (compare >= 0);
                                } else if (op == CompareOp.GREATER_THAN) {
                                    match = (compare >= 0);
                                } else if (op == CompareOp.LESS_OR_EQUAL) {
                                    match = (compare <= 0);
                                } else if (op == CompareOp.LESS_THAN) {
                                    match = (compare < 0);
                                }
                            }
                        }

                        if (match) {
                            vars.put(item.varName, node);
                        }
                    }
                }
            }
        }

        return match;
    }

    private static Map<String, Future<?>> actionTask = new HashMap<>();

    private void evaluateAction(LogicItem item, Map<String, AccessibilityNodeInfo> vars) {
        ActionType at = ActionType.fromDisplayName(item.actionType);
        if (at != null) {
            Double delay = item.delay;

            if (at == ActionType.CLICK) {
                String target = item.target;
                AccessibilityNodeInfo node = vars.get(target);
                if (node != null) {
                    runAction(delay, () -> {
                        clickByNodeCenter(node);
                    });
                }
            } else if (at == ActionType.BACK) {
                runAction(delay, () -> {
                    performBack();
                });
            } else if(at == ActionType.SWIPE_UP){
                runAction(delay, () -> {
                    swipeUp();
                });
            } else if(at == ActionType.SWIPE_DOWN){
                runAction(delay, () -> {
                    swipeDown();
                });
            }else if(at == ActionType.SWIPE_LEFT){
                runAction(delay, () -> {
                    swipeLeft();
                });
            }else if(at == ActionType.SWIPE_RIGHT){
                runAction(delay, () -> {
                    swipeRight();
                });
            }

        }

    }

    private void runAction(double delay, Runnable runnable) {
        String key = threadLocal.get().getKey();
        if (Double.compare(delay, 0.0) == 0) {
            mainHandler.post(() -> {
                runnable.run();
            });
        } else {
            if (actionTask.get(key) == null) {
                Future<?> submit = executor.submit(() -> {
                    try {
                        Double d = delay * 1000.0;
                        Thread.sleep(d.intValue());
                        mainHandler.post(() -> {
                            runnable.run();
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        actionTask.remove(key);
                    }
                });
                actionTask.put(key, submit);
            }
        }
    }

    public void clickByNodeCenter(AccessibilityNodeInfo node) {

        Rect rect = new Rect();
        node.getBoundsInScreen(rect);

        // 校验 bounds 合法性
        if (rect.left < 0 || rect.top < 0 || rect.right <= rect.left || rect.bottom <= rect.top) {
            Log.w("MyAccessibilityService", "点击跳过：坐标非法 " + rect.toShortString());
            return;
        }

        Path path = new Path();
        path.moveTo(rect.centerX(), rect.centerY());

        GestureDescription.StrokeDescription stroke =
                new GestureDescription.StrokeDescription(path, 0, 100);

        GestureDescription gesture =
                new GestureDescription.Builder().addStroke(stroke).build();

        this.dispatchGesture(gesture, null, null);
    }

    public void performBack() {
        performGlobalAction(AccessibilityService.GLOBAL_ACTION_BACK);
    }

    // 查找所有 text 等于指定内容的节点
    public static List<AccessibilityNodeInfo> findNodesByTextEquals(AccessibilityNodeInfo root, String text) {
        List<AccessibilityNodeInfo> result = new ArrayList<>();
        if (root == null) return result;

        CharSequence nodeText = root.getText();
        CharSequence desc = root.getContentDescription();

        if ((nodeText != null && nodeText.toString().equals(text)) ||
                (desc != null && desc.toString().equals(text))) {
            if(root.isVisibleToUser()){
                result.add(root);
                return result;
            }
        }

        for (int i = 0; i < root.getChildCount(); i++) {
            AccessibilityNodeInfo child = root.getChild(i);
            result.addAll(findNodesByTextEquals(child, text));
        }

        return result;
    }

    // 查找所有 text 以指定内容开头的节点
    public static List<AccessibilityNodeInfo> findNodesByTextStartsWith(AccessibilityNodeInfo root, String text) {
        List<AccessibilityNodeInfo> result = new ArrayList<>();
        if (root == null) return result;

        CharSequence nodeText = root.getText();
        CharSequence desc = root.getContentDescription();

        if ((nodeText != null && nodeText.toString().startsWith(text)) ||
                (desc != null && desc.toString().startsWith(text))) {
            if(root.isVisibleToUser()){
                result.add(root);
                return result;
            }
        }

        for (int i = 0; i < root.getChildCount(); i++) {
            AccessibilityNodeInfo child = root.getChild(i);
            result.addAll(findNodesByTextStartsWith(child, text));
        }

        return result;
    }

    // 查找所有 text 以指定内容结尾的节点
    public static List<AccessibilityNodeInfo> findNodesByTextEndsWith(AccessibilityNodeInfo root, String text) {
        List<AccessibilityNodeInfo> result = new ArrayList<>();
        if (root == null) return result;

        CharSequence nodeText = root.getText();
        CharSequence desc = root.getContentDescription();

        if ((nodeText != null && nodeText.toString().endsWith(text)) ||
                (desc != null && desc.toString().endsWith(text))) {
            if(root.isVisibleToUser()){
                result.add(root);
                return result;
            }

        }

        for (int i = 0; i < root.getChildCount(); i++) {
            AccessibilityNodeInfo child = root.getChild(i);
            result.addAll(findNodesByTextEndsWith(child, text));
        }

        return result;
    }


    /**
     * 执行滑动操作（可控制滑动距离比例）
     * @param direction     滑动方向（GestureDirection常量）
     * @param durationMs    滑动持续时间（毫秒）
     * @param distanceRatio 滑动距离比例（0.1~1.0，例如0.5表示滑动控件宽度/高度的一半）
     */
    private void performSwipe(
            int direction,
            int durationMs,
            float distanceRatio
    ) {
        // 参数校验
        if (distanceRatio <= 0 || distanceRatio > 1) {
            throw new IllegalArgumentException("distanceRatio must be in (0, 1]");
        }

        Rect bounds = new Rect();

        DisplayMetrics metrics = getResources().getDisplayMetrics();
        bounds.set(0, 0, metrics.widthPixels, metrics.heightPixels);

        int startX, startY, endX, endY;
        int horizontalMargin = (int) (bounds.width() * 0.1f); // 水平边距10%
        int verticalMargin = (int) (bounds.height() * 0.1f);  // 垂直边距10%

        switch (direction) {
            case GestureDirection.SWIPE_LEFT:
                startX = bounds.right - horizontalMargin;
                endX = bounds.left + (int)(bounds.width() * (1 - distanceRatio));
                startY = endY = bounds.centerY();
                break;
            case GestureDirection.SWIPE_RIGHT:
                startX = bounds.left + horizontalMargin;
                endX = bounds.right - (int)(bounds.width() * (1 - distanceRatio));
                startY = endY = bounds.centerY();
                break;
            case GestureDirection.SWIPE_UP:
                startY = bounds.bottom - verticalMargin;
                endY = bounds.top + (int)(bounds.height() * (1 - distanceRatio));
                startX = endX = bounds.centerX();
                break;
            case GestureDirection.SWIPE_DOWN:
                startY = bounds.top + verticalMargin;
                endY = bounds.bottom - (int)(bounds.height() * (1 - distanceRatio));
                startX = endX = bounds.centerX();
                break;
            default:
                throw new IllegalArgumentException("Invalid direction");
        }

        // 确保终点不会超出边界
        endX = Math.max(bounds.left, Math.min(bounds.right, endX));
        endY = Math.max(bounds.top, Math.min(bounds.bottom, endY));

        Path path = new Path();
        path.moveTo(startX, startY);
        path.lineTo(endX, endY);

        GestureDescription gesture = new GestureDescription.Builder()
                .addStroke(new GestureDescription.StrokeDescription(path, 0, durationMs))
                .build();

        dispatchGesture(gesture, null, null);
    }

    public class GestureDirection {
        public static final int SWIPE_LEFT = 0;
        public static final int SWIPE_RIGHT = 1;
        public static final int SWIPE_UP = 2;
        public static final int SWIPE_DOWN = 3;

        // 默认参数（直接内联到方法中）
        private static final int DEFAULT_DURATION_MS = 500;
        private static final float DEFAULT_SWIPE_RATIO = 0.7f;
        private static final float EDGE_MARGIN_RATIO = 0.1f;
    }

    // 左滑（70%距离，500ms）
    public void swipeLeft() {
        performSwipe(GestureDirection.SWIPE_LEFT, GestureDirection.DEFAULT_DURATION_MS, GestureDirection.DEFAULT_SWIPE_RATIO);
    }

    // 右滑（70%距离，500ms）
    public void swipeRight() {
        performSwipe(GestureDirection.SWIPE_RIGHT, GestureDirection.DEFAULT_DURATION_MS, GestureDirection.DEFAULT_SWIPE_RATIO);
    }

    // 上滑（70%距离，500ms）
    public void swipeUp() {
        performSwipe(GestureDirection.SWIPE_UP, GestureDirection.DEFAULT_DURATION_MS, GestureDirection.DEFAULT_SWIPE_RATIO);
    }

    // 下滑（70%距离，500ms）
    public void swipeDown() {
        performSwipe(GestureDirection.SWIPE_DOWN, GestureDirection.DEFAULT_DURATION_MS, GestureDirection.DEFAULT_SWIPE_RATIO);
    }


    class LogicItemContext {
        public String packageName;
        public int index;

        public LogicItemContext(String packageName, int index) {
            this.packageName = packageName;
            this.index = index;
        }

        public String getKey() {
            return packageName + "-" + index;
        }
    }


}
